package com.bsj.power.system.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.bsj.power.common.config.cached.*;
import com.bsj.power.common.config.exception.ApiException;
import com.bsj.power.common.config.global.JsonResultEnum;
import com.bsj.power.common.config.global.TokenUser;
import com.bsj.power.common.config.redis.RedisConstant;
import com.bsj.power.common.constant.ApiConstants;
import com.bsj.power.common.constant.NumericalConstants;
import com.bsj.power.common.def.dto.cardReport.BindCardDTO;
import com.bsj.power.common.def.dto.open.OpenV1DTO;
import com.bsj.power.common.def.entity.job.Job;
import com.bsj.power.common.def.entity.job.QualityPlan;
import com.bsj.power.common.def.entity.job.WorkPersonnel;
import com.bsj.power.common.def.entity.locationDevice.LocationDevice;
import com.bsj.power.common.def.entity.locationDevice.LocationDeviceLog;
import com.bsj.power.common.def.entity.menu.Menu;
import com.bsj.power.common.def.entity.menu.RoleMenu;
import com.bsj.power.common.def.entity.personnel.Personnel;
import com.bsj.power.common.def.entity.portalLoginLog.PortalLoginLog;
import com.bsj.power.common.def.entity.role.Role;
import com.bsj.power.common.def.entity.syncLog.SyncLog;
import com.bsj.power.common.def.entity.user.User;
import com.bsj.power.common.def.http.dto.WorkHttpDTO;
import com.bsj.power.common.def.vo.pls.httpVo.HttpLoginPersonVO;
import com.bsj.power.common.def.vo.pls.httpVo.HttpTagInfoVO;
import com.bsj.power.common.http.ExternalAccessHttp;
import com.bsj.power.common.http.LoginPersonHttp;
import com.bsj.power.common.mapper.*;
import com.bsj.power.common.util.DataUtil;
import com.bsj.power.common.util.DateUtils;
import com.bsj.power.system.config.open.OpenApiConfig;
import com.bsj.power.system.service.OpenApiService;
import com.bsj.tools.HexStr;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import redis.clients.bsj.JedisClusterBSJ;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author yinhao
 * @version 1.0
 * @description 开放接口
 * @date 2024/7/11
 */
@Service
@Slf4j
public class OpenApiServiceImpl implements OpenApiService {

    /**
     * 固定的三种工单状态，第一次同步时只需要同步这三种
     */
    private static final List<String> SYNC_STATUS_LIST = List.of("INPRG", "ASSIGN1", "PREPARE1");

    /**
     * 工号固定前缀
     */
    private static final String EMP_NO_PREFIX = "S";
    private static final String EMP_NO_SUFFIX = "E";

    @Autowired
    private OpenApiConfig openApiConfig;

    @Autowired
    private LoginPersonHttp loginPersonHttp;

    @Resource
    private UserMapper userMapper;

    @Resource
    private JobMapper jobMapper;

    @Resource
    private QualityPlanMapper qualityPlanMapper;

    @Resource
    private PersonnelMapper personnelMapper;

    @Autowired
    private PersonnelCached personnelCached;

    @Autowired
    private RedisCached redisCached;

    @Autowired
    private LocationDeviceCached locationDeviceCached;

    @Resource
    private LocationDeviceMapper locationDeviceMapper;

    @Resource
    private SyncLogMapper syncLogMapper;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private RoleMenuMapper roleMenuMapper;

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private WorkPersonnelMapper workPersonnelMapper;

    @Autowired
    private WorkPersonnelCached workPersonnelCached;

    @Autowired
    private JedisClusterBSJ jedisClusterBSJ;

    @Autowired
    private BindCardCached bindCardCached;

    @Resource
    private PortalLoginLogMapper portalLoginLogMapper;

    @Resource
    private LocationDeviceLogMapper locationDeviceLogMapper;

    /**
     * 第三方授权
     *
     * @param request
     * @param dto
     * @return
     */
    @Override
    public String loginUrl(HttpServletRequest request, OpenV1DTO dto) {
//        log.info("参数信息{}", dto);
        PortalLoginLog portalLoginLog = new PortalLoginLog();
        String inParameter = getDecodeParam(dto);
        Date date = new Date();
        portalLoginLog.setInParameter(inParameter);
        portalLoginLog.setLoginTime(date);
        portalLoginLog.setIsSuccess(NumericalConstants.TWO);
        portalLoginLog.setIp(ServletUtil.getClientIP(request, null));
        AES aes = SecureUtil.aes(HexStr.toArray(openApiConfig.aesKey));
        String loginid = aes.decryptStr(dto.getLoginid());
        portalLoginLog.setLoginId(loginid);
        String workcode = dto.getWorkcode();
        User user = userMapper.selectByLoginId(loginid);
        if (user == null) {
            portalLoginLog.setRemark("门户账号不存在");
            portalLoginLogMapper.insert(portalLoginLog);
            throw new ApiException(JsonResultEnum.USER_INFO_MATE_FAILED);
        }
        Integer userType = user.getUserType();
        if (userType == null || !userType.equals(NumericalConstants.ONE)) {
            portalLoginLog.setRemark("非门户账号登录");
            portalLoginLogMapper.insert(portalLoginLog);
            throw new ApiException(JsonResultEnum.USER_INFO_MATE_FAILED);
        }
        if (user.getIsAccess().equals(NumericalConstants.TWO)) {
            portalLoginLog.setRemark("账号被禁止访问");
            portalLoginLogMapper.insert(portalLoginLog);
            throw new ApiException(JsonResultEnum.PERMISSION_EXCEPTION);
        }
        if (DateUtils.differentDays(user.getLastLoginTime(), date) >= 90) {
            user.setIsAccess(NumericalConstants.TWO);
            userMapper.updateById(user);
            portalLoginLog.setRemark("账号90天未登录本平台，已被禁止访问");
            portalLoginLogMapper.insert(portalLoginLog);
            throw new ApiException(JsonResultEnum.PERMISSION_EXCEPTION);
        }
//        log.info("用户信息{}", user);
        if (StringUtils.isNotBlank(workcode) && !user.getWorkCode().equals(aes.decryptStr(workcode))) {
            portalLoginLog.setRemark("登录编号不正确");
            portalLoginLogMapper.insert(portalLoginLog);
            throw new ApiException(JsonResultEnum.USER_INFO_MATE_FAILED);
        }
        //外部授权成功，需要写入登录信息
        StpUtil.login(user.getUserId());
        String tokenValue = StpUtil.getTokenValue();
        //半小时过期
//        StpUtil.renewTimeout(tokenValue, 30 * 60);
        TokenUser tokenUser = new TokenUser();
        tokenUser.setUserId(user.getUserId());
        //外部授权人员
        tokenUser.setUserType(NumericalConstants.ONE);
        tokenUser.setUserName(loginid);
        tokenUser.setSessionId(tokenValue);

        List<Long> roleIds = userRoleMapper.selectUserRoleIdList(user.getUserId());
        if (!roleIds.isEmpty()) {
            List<Role> roleInfos = roleMapper.selectBatchIds(roleIds);
            //目前是一个用户只有一个角色
            if (!roleInfos.isEmpty()) {
                Role role = roleInfos.get(0);
                tokenUser.setRoleSign(role.getRoleSign());
                tokenUser.setRoleType(role.getRoleType());
                Long roleId = role.getRoleId();
                List<RoleMenu> roleMenus = roleMenuMapper.selectList(Wrappers.<RoleMenu>lambdaQuery().eq(RoleMenu::getRoleId, roleId));
                if (!roleMenus.isEmpty()) {
                    List<Integer> menuIds = roleMenus.stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
                    List<Menu> menus = menuMapper.selectList(Wrappers.<Menu>lambdaQuery().in(Menu::getMenuId, menuIds));
                    if (!menus.isEmpty()) {
                        List<String> menuSigns = menus.stream().map(Menu::getMenuSign).collect(Collectors.toList());
                        tokenUser.setMenuSigns(menuSigns);
                    }
                }
            }
        }

        user.setLastLoginTime(date);
        userMapper.updateById(user);

//        List<String> permissions = Arrays.asList(SysModulePermissionEnum.values()).stream().map(SysModulePermissionEnum::getValue).collect(Collectors.toList());
//        tokenUser.setPermissions(permissions);
        //登录信息保存方式一样，不同点在于权限选择时的LoginType跟登陆后的用户类型区分
        StpUtil.getTokenSession().set("loginUser", tokenUser);
        //返回的参数也是加密过的信息
        String encryptHex = aes.encryptHex(openApiConfig.v1Url + tokenValue);
//        log.info("跳转地址：{}", openApiConfig.v1Url + tokenValue);
//        log.info("sessionId信息：{}", tokenValue);
        portalLoginLog.setIsSuccess(NumericalConstants.ONE);
        portalLoginLog.setRemark("登录成功");
        //出参
        portalLoginLog.setOutParameter(getOutParameter(new StringBuilder(tokenValue)));
        portalLoginLogMapper.insert(portalLoginLog);
        return encryptHex;
    }

    /**
     * 获取出参
     *
     * @param builder
     * @return java.lang.String
     * @author ljx
     * @time 2024/10/14 20:34
     */
    private String getOutParameter(StringBuilder builder) {
        builder = builder.replace(2, 6, "****");
        builder = builder.replace(10, 12, "**");
        builder = builder.replace(15, 17, "**");
        builder = builder.replace(15, 17, "**");
        builder = builder.replace(20, 22, "**");
        builder = builder.replace(28, 31, "****");
        return openApiConfig.v1Url + builder;
    }

    /**
     * 获取解密后的参数
     *
     * @param dto
     * @return java.lang.String
     * @author ljx
     * @time 2024/10/14 17:23
     */
    private String getDecodeParam(OpenV1DTO dto) {
        AES aes = SecureUtil.aes(HexStr.toArray(openApiConfig.aesKey));
        String loginid = aes.decryptStr(dto.getLoginid());
        String workcode = StringUtils.isNotBlank(dto.getWorkcode()) ? aes.decryptStr(dto.getWorkcode()) : "";
        OpenV1DTO openV1DTO = new OpenV1DTO(loginid, workcode, dto.getTimestamp(), dto.getSign(), dto.getRequestId());
        return JSON.toJSONString(openV1DTO);
    }

    /**
     * 定时同步用户信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncHrmUserInfo() {
        List<HttpLoginPersonVO> httpLoginPersonVOList = new ArrayList<>();
        String method = "/api/hrm/resful/getHrmUserInfoWithPage";
        JSONObject hrmUserInfo = new JSONObject();
        hrmUserInfo.put("curpage", 1);
        hrmUserInfo.put("pagesize", 1000);
        Boolean flag = true;
        while (flag) {
            String postRestful = loginPersonHttp.postRestful(openApiConfig.loginPersonUrl, method, JSONObject.toJSONString(Map.of("params", hrmUserInfo)), openApiConfig.loginAppId);
//            log.info("登录人员接口json字符串格式信息{}", postRestful);
            JSONObject restfulJson = JSONObject.parseObject(postRestful);
//            log.info("登录人员接口返回信息{}", postRestful);
            // 1 成功，其他失败
            String code = restfulJson.getString("code");
            if (!code.equalsIgnoreCase("1")) {
                log.warn("系统人员信息同步失败: {}", code);
                break;
            }
            JSONObject dataJson = restfulJson.getJSONObject("data");
            // 分页-总数
            Integer totalSize = dataJson.getInteger("totalSize");
            // 分页-单页条目数
            Integer pageSize = dataJson.getInteger("pageSize");
            // 分页-当前页数
            Integer page = dataJson.getInteger("page");
            JSONArray dataList = dataJson.getJSONArray("dataList");
            List<HttpLoginPersonVO> httpLoginPersonVOS = dataList.toJavaList(HttpLoginPersonVO.class);
            httpLoginPersonVOList.addAll(httpLoginPersonVOS);
            if (httpLoginPersonVOList.size() >= totalSize) {
                break;
            }
            //读取下一页数据
            hrmUserInfo.put("curpage", page + 1);
        }
        User adminUser = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getParentId, NumericalConstants.NEGATIVE_ONE));
        Long adminUserId = adminUser.getUserId();
        //同步更新，判定新增还是更新
        List<User> users = userMapper.selectList(Wrappers.<User>lambdaQuery().eq(User::getUserType, 1).orderByDesc(User::getCreateTime));
        Map<String, User> userMap = new HashMap<>();
        Map<String, User> userNameMap = new HashMap<>();
        users.forEach(user -> {
            userMap.put(user.getId(), user);
            userNameMap.put(user.getUserName(), user);
        });
        //新增集合
        List<User> addUserList = new ArrayList<>();
        //更新集合
        List<User> updateUserList = new ArrayList<>();
        for (HttpLoginPersonVO info : httpLoginPersonVOList) {
            String loginid = info.getLoginid();
            if (StringUtils.isBlank(loginid)) {
                continue;
            }
            User changeUser = info.change();
            String userName = changeUser.getUserName();
            User oldUser = userNameMap.get(userName);
            //防止账号重复
            if (oldUser != null) {
                changeUser.setUserName(userName + NumericalConstants.ONE);
            }
            String id = info.getId();
            User user = userMap.get(id);
            if (user != null && user.getCreateTime().getTime() < DateUtils.strToDate(info.getModified()).getTime()) {
                //需要更新数据,不变更密码与访问权限
                changeUser.setUserId(user.getUserId());
                changeUser.setPassword(null);
                updateUserList.add(changeUser);
            } else if (user == null) {
                //新增
                changeUser.setParentId(adminUserId);
                addUserList.add(changeUser);
            }
        }
        if (!addUserList.isEmpty()) {
            userMapper.batchInsert(addUserList);
        }
        if (!updateUserList.isEmpty()) {
            userMapper.batchUpdate(updateUserList);
        }
    }

    /**
     * 工单同步定时任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncSysWorkList() {
        WorkHttpDTO workHttpDTO = WorkHttpDTO.builder().pageNum(1).pageSize(1000).type(1).build();
        List<Job> jobList = ExternalAccessHttp.workInfoHttpGet(openApiConfig.syncJobUrl, workHttpDTO);
//        log.info("工单信息请求结束...");
        if (jobList.isEmpty()) {
            return;
        }
        //已有的工单，工单去重
        Set<String> oldJobNumList = redisCached.smembers(RedisConstant.JOB_NUM_SET);
        //去重后的工单
        List<Job> addJobList = new LinkedList<>();
        //负责人员id集
        List<String> directorIds = new LinkedList<>();
        //工单号集
        List<String> jobNums = new LinkedList<>();
        for (Job job : jobList) {
            String jobNum = job.getJobNum();
            String directorId = job.getDirectorId();
            if (StringUtils.isAnyBlank(jobNum, directorId, job.getWorkArea(), job.getRoomNo()) || job.getStartTime() == null || job.getUnitNum() == null) {
                continue;

            }
            //P开头的不需要同步
            if (jobNum.substring(NumericalConstants.ZERO, NumericalConstants.ONE).toUpperCase().equals("P")) {
                continue;
            }
            //已存在无需同步
            if (!CollectionUtils.isEmpty(oldJobNumList) && oldJobNumList.contains(jobNum)) {
                continue;
            }
            jobNums.add(jobNum);
            //负责人员信息
            directorIds.add(directorId);
            addJobList.add(job);
        }
        if (CollectionUtils.isEmpty(addJobList)) {
            SyncLog syncLog = new SyncLog(NumericalConstants.ZERO);
            syncLogMapper.insert(syncLog);
            return;
        }

        //质量计划
        List<QualityPlan> qualityPlanList = new LinkedList<>();
        //人员信息（负责人）
        List<Personnel> personnelList = new LinkedList<>();

        //分批请求质量计划，每批100
        List<List<String>> jobNumLists = DataUtil.splitData(jobNums, 100);
        for (List<String> jobNumList : jobNumLists) {
            String join = String.join(",", jobNumList);
            List<QualityPlan> qualityPlans = ExternalAccessHttp.qualityPlanInfoHttpGet(openApiConfig.syncJobUrl, join);
            if (!CollectionUtils.isEmpty(qualityPlans)) {
                qualityPlanList.addAll(qualityPlans);
            }
        }
        if (!CollectionUtils.isEmpty(directorIds)) {
            //分批请求负责人员，每批100
            List<List<String>> directorIdLists = DataUtil.splitData(directorIds, 100);
            for (List<String> directorIdList : directorIdLists) {
                String join = String.join(",", directorIdList);
                List<Personnel> list = ExternalAccessHttp.personnelInfoHttpGet(openApiConfig.syncJobUrl, join);
                if (!CollectionUtils.isEmpty(list)) {
//                    log.info("本批负责人同步数目：{}", list.size());
                    personnelList.addAll(list);
                }
            }
        }
//        log.info("数据获取完成：工单数量{}", jobList.size());
//        log.info("实际待添加工单数量{}", !addJobList.isEmpty() ? addJobList.size() : 0);
        List<List<Job>> lists = DataUtil.splitData(addJobList, 1000);
        Integer total = NumericalConstants.ZERO;
        for (List<Job> list : lists) {
            Integer sysJobList = jobMapper.syncInsertSysJobList(list);
//            log.info("工单定时同步数据数目： {}", sysJobList);
            total += sysJobList;
        }
//        //每个工单对应的质量计划集
//        log.info("质量数量{}", !qualityPlanList.isEmpty() ? qualityPlanList.size() : 0);
        if (!CollectionUtils.isEmpty(qualityPlanList)) {
            Integer qualityPlanTotal = qualityPlanMapper.batchAdd(qualityPlanList);
//            log.info("质量计划定时同步数据数目： {}", qualityPlanTotal);
        }

//        log.info("负责人员数量{}", !personnelList.isEmpty() ? personnelList.size() : 0);
        String strValue = redisCached.get(RedisConstant.EMP_NO_LAST_NUMBER);
//        log.info("当前工号最后停留的编号数值：{}", strValue);
        Integer value = Integer.parseInt(strValue);
        if (!CollectionUtils.isEmpty(personnelList)) {
            personnelList = personnelList.stream().collect(Collectors.toMap(Personnel::getDirectorId, a -> a, (k1, k2) -> k1)).values().stream().collect(Collectors.toList());
            List<Personnel> addPersonnelList = new LinkedList<>();
            //重复的不添加
            List<Personnel> personnelCachedList = personnelCached.hgetAllPersonnelInfo();
            List<String> empNoList = new LinkedList<>();
            if (!CollectionUtils.isEmpty(personnelCachedList)) {
                empNoList = personnelCachedList.stream().map(Personnel::getEmpNo).collect(Collectors.toList());
                List<String> idCardNoList = personnelCachedList.stream().map(Personnel::getIdCardNo).collect(Collectors.toList());
                Map<String, Personnel> personnelMap = personnelCachedList.stream().collect(Collectors.toMap(Personnel::getDirectorId, Function.identity(), (v1, v2) -> v2));
                for (Personnel personnel : personnelList) {
                    //身份证已存在则跳过
                    String idCardNo = personnel.getIdCardNo();
                    if (StringUtils.isNotBlank(idCardNo) && idCardNoList.contains(idCardNo)) {
                        continue;
                    }
                    //为空代表需要添加
                    if (personnelMap.get(personnel.getDirectorId()) == null) {
                        if (StringUtils.isBlank(personnel.getEmpNo())) {
                            //生成工号，最多设置八位数
                            value = getValue(empNoList, value);
                            String empNo = EMP_NO_PREFIX + String.format("%08d", value) + EMP_NO_SUFFIX;
                            personnel.setEmpNo(empNo);
                            empNoList.add(empNo);
                            value += 1;
                        }
                        addPersonnelList.add(personnel);
                    }
                }
            } else {
                for (Personnel personnel : personnelList) {
                    //为空代表需要添加
                    if (StringUtils.isBlank(personnel.getEmpNo())) {
                        //生成工号，最多设置八位数
                        value = getValue(empNoList, value);
                        String empNo = EMP_NO_PREFIX + String.format("%08d", value) + EMP_NO_SUFFIX;
                        personnel.setEmpNo(empNo);
                        empNoList.add(empNo);
                        value += 1;
                    }
                    addPersonnelList.add(personnel);
                }
            }

            if (!CollectionUtils.isEmpty(addPersonnelList)) {
                Integer personnelTotal = personnelMapper.batchAdd(addPersonnelList);
                personnelCached.hsetAllPersonnelInfo(addPersonnelList);
//                log.info("负责人员定时同步数据数目： {}", personnelTotal);
            }
        }

        SyncLog syncLog = new SyncLog(total);
        syncLogMapper.insert(syncLog);
        redisCached.set(RedisConstant.EMP_NO_LAST_NUMBER, value);

        List<Personnel> allPersonnel = personnelCached.hgetAllPersonnelInfo();
        Map<String, Personnel> personnelMap = null;
        if (!CollectionUtils.isEmpty(allPersonnel)) {
            personnelMap = personnelList.stream().collect(Collectors.toMap(Personnel::getDirectorId, a -> a, (k1, k2) -> k1));
        }

        //工单信息缓存
        for (Job job : addJobList) {
            Long jobId = job.getJobId();
            redisCached.sadd(RedisConstant.JOB_NUM_SET, job.getJobNum());
            //由于以下三个字段的数据太长，存在redis也用不到，所以置空
            job.setProcedure(null);
            job.setRisk(null);
            job.setPrecautionaryMeasures(null);
            redisCached.hset(RedisConstant.JOB_ORDER_INFO_KEY, jobId + "", JSON.toJSONString(job));
            // 敏感区域的工单需要额外存储
            if (job.getAreaType().equals(NumericalConstants.ONE)) {
                if (!CollectionUtils.isEmpty(personnelMap)) {
                    Personnel personnel = personnelMap.get(job.getDirectorId());
                    if (personnel != null) {
                        job.setEmpNo(personnel.getEmpNo());
                    }
                }
                redisCached.hset(RedisConstant.JOB_ROOM_NO_INFO_KEY + job.getRoomNo(), jobId + "", JSON.toJSONString(job));
            }
        }
    }

    /**
     * 获取当前工号编号
     *
     * @param empNoList
     * @param value
     * @return java.lang.Integer
     * @author ljx
     * @time 2024/8/27 16:14
     */
    private static Integer getValue(List<String> empNoList, Integer value) {
        String empNo = EMP_NO_PREFIX + String.format("%08d", value) + EMP_NO_SUFFIX;
        if (empNoList.contains(empNo)) {
            value += 1;
            value = getValue(empNoList, value);
        }
        return value;
    }

    /**
     * 同步设备信息
     *
     * @return void
     * @author ljx
     * @time 2024/8/9 9:22
     */
    @Override
    @Transactional
    public void syncDeviceInfo() {
        List<LocationDevice> addLocationDevices = new LinkedList<>();
        List<LocationDevice> locationDevices = ExternalAccessHttp.locationDeviceInfoHttpGet(openApiConfig.ipHost);
        if (!CollectionUtils.isEmpty(locationDevices)) {
            List<LocationDevice> oldLocationDevices = locationDeviceCached.hgetAllLocationDeviceInfo();
            Map<String, LocationDevice> deviceMap = null;
            if (!CollectionUtils.isEmpty(oldLocationDevices)) {
                deviceMap = oldLocationDevices.stream().collect(Collectors.toMap(LocationDevice::getDeviceName, Function.identity()));
            }
            for (LocationDevice locationDevice : locationDevices) {
                if (!CollectionUtils.isEmpty(deviceMap) && deviceMap.get(locationDevice.getDeviceName()) != null) {
                    continue;
                }
                addLocationDevices.add(locationDevice);
            }
        }
        if (!CollectionUtils.isEmpty(addLocationDevices)) {
            int size1 = addLocationDevices.stream().filter(locationDevice -> locationDevice.getDeviceType().equals(NumericalConstants.ONE)).collect(Collectors.toList()).size();
            int size2 = addLocationDevices.stream().filter(locationDevice -> locationDevice.getDeviceType().equals(NumericalConstants.TWO)).collect(Collectors.toList()).size();
            Integer count = locationDeviceMapper.batchAdd(addLocationDevices);
//            log.info("设备同步总数{}", count);
            addLocationDevices.forEach(locationDevice -> locationDeviceCached.hsetLocationDeviceInfo(locationDevice));
        }
    }

    /**
     * 同步修改工单信息
     *
     * @return void
     * @author ljx
     * @time 2024/8/10 14:09
     */
    @Override
    @Transactional
    public void syncUpdateSysWorkList() {
        List<Job> updateJobList = new LinkedList<>();
        Map<String, String> map = redisCached.hgetAll(RedisConstant.JOB_ORDER_INFO_KEY);
        if (!CollectionUtils.isEmpty(map)) {
            //未完成的工单
            Map<String, Job> jobMap = new HashMap<>();
            //未完成的工单号
            List<String> woNumList = new LinkedList<>();
            for (String str : map.values()) {
                Job job = JSONObject.parseObject(str, Job.class);
                String jobNum = job.getJobNum();
                //只修改未完成的工单
                if (!job.getStatus().equals(NumericalConstants.TWO)) {
                    woNumList.add(jobNum);
                    jobMap.put(jobNum, job);
                }
            }
            //负责人员id集
            List<String> directorIds = new LinkedList<>();
            if (!CollectionUtils.isEmpty(woNumList)) {
                log.info("未完成工单数量:{}", woNumList.size());
                List<List<String>> lists = DataUtil.splitData(woNumList, 100);
                List<Job> jobList = ExternalAccessHttp.updateWorkInfoHttpGet(openApiConfig.syncJobUrl, lists);
                if (!CollectionUtils.isEmpty(jobList)) {
//                    log.info("同步待修改工单信息数量{}", jobList.size());
                    for (Job job : jobList) {
                        String jobNum = job.getJobNum();
                        String directorId = job.getDirectorId();
                        if (job.getStartTime() == null || job.getUnitNum() == null || StringUtils.isAnyBlank(jobNum, directorId, job.getWorkArea(), job.getRoomNo())) {
                            continue;
                        }
                        //P开头的不需要同步
                        if (jobNum.substring(NumericalConstants.ZERO, NumericalConstants.ONE).toUpperCase().equals("P")) {
                            continue;
                        }
                        Job oldJob = jobMap.get(jobNum);
                        if (oldJob != null) {
                            job.setJobId(oldJob.getJobId());
                            String syncStatus = job.getSyncStatus();
                            if (StringUtils.isNotBlank(syncStatus) && !SYNC_STATUS_LIST.contains(syncStatus)) {
                                job.setStatus(NumericalConstants.TWO);
                            }
                            directorIds.add(directorId);
                            updateJobList.add(job);
                        }
                    }
                }
            }
            if (!CollectionUtils.isEmpty(updateJobList)) {
                List<List<Job>> lists = DataUtil.splitData(updateJobList, 1000);
                for (List<Job> list : lists) {
                    jobMapper.batchUpdate(list);
                }
                updateJobList.forEach(job -> {
                    //由于以下三个字段的数据太长，存在redis也用不到，所以置空
                    job.setProcedure(null);
                    job.setRisk(null);
                    job.setPrecautionaryMeasures(null);
                    Long jobId = job.getJobId();
                    redisCached.hset(RedisConstant.JOB_ORDER_INFO_KEY, jobId + "", JSON.toJSONString(job));
                    //已完成的工单需要删除敏感区域工单信息缓存
                    if (job.getStatus().equals(NumericalConstants.TWO)) {
                        redisCached.hdel(RedisConstant.JOB_ROOM_NO_INFO_KEY + job.getRoomNo(), jobId + "");
                    }
                });
            }
//            //人员信息（负责人）
//            List<Personnel> personnelList = new LinkedList<>();
//            if (!CollectionUtils.isEmpty(directorIds)) {
//                //分批请求负责人员，每批100
//                List<List<String>> directorIdLists = DataUtil.splitData(directorIds, 100);
//                for (List<String> directorIdList : directorIdLists) {
//                    String join = String.join(",", directorIdList);
//                    List<Personnel> list = ExternalAccessHttp.personnelInfoHttpGet(openApiConfig.syncJobUrl, join);
//                    if (!CollectionUtils.isEmpty(list)) {
//                        personnelList.addAll(list);
//                    }
//                }
//                if (!CollectionUtils.isEmpty(personnelList)) {
//                    List<Personnel> addPersonnelList = new LinkedList<>();
//                    List<Personnel> updatePersonnelList = new LinkedList<>();
//                    //去重
//                    personnelList = personnelList.stream().collect(Collectors.toMap(Personnel::getDirectorId, a -> a, (k1, k2) -> k1)).values().stream().collect(Collectors.toList());
//                    //重复的不添加
//                    List<Personnel> personnelCachedList = personnelCached.hgetAllPersonnelInfo();
//                    if (!CollectionUtils.isEmpty(personnelCachedList)) {
//                        Map<String, Personnel> personnelMap = personnelCachedList.stream().collect(Collectors.toMap(Personnel::getDirectorId, Function.identity(), (v1, v2) -> v2));
//                        for (Personnel personnel : personnelList) {
//                            String newEmpNo = personnel.getEmpNo();
//                            Personnel oldPersonnel = personnelMap.get(personnel.getDirectorId());
//                            if (oldPersonnel == null) {
//                                //新加负责人
//                                if (StringUtils.isBlank(newEmpNo)) {
//                                    //TODO 生成工号
//                                    personnel.setEmpNo(null);
//                                }
//                                addPersonnelList.add(personnel);
//                            } else {
//                                //TODO 修改负责人，工号处理待添加
//                                String oldEmpNo = oldPersonnel.getEmpNo();
//                                if (StringUtils.isBlank(newEmpNo)) {
//                                    if (StringUtils.isBlank(oldEmpNo)) {
//                                        //TODO 生成工号
//                                    } else {
//                                        personnel.setEmpNo(oldEmpNo);
//                                    }
//                                }
//                            }
//                            personnel.setPersonnelId(oldPersonnel.getPersonnelId());
//                            updatePersonnelList.add(personnel);
//                        }
//                    }
//                    if (!CollectionUtils.isEmpty(addPersonnelList)) {
//                        Integer personnelTotal = personnelMapper.batchAdd(addPersonnelList);
//                        personnelCached.hsetAllPersonnelInfo(addPersonnelList);
//                        log.info("修改工单时负责人员定时同步数据数目： {}", personnelTotal);
//                    }
//                    if (!CollectionUtils.isEmpty(updatePersonnelList)) {
//                        Integer personnelTotal = personnelMapper.batchUpdate(updatePersonnelList);
//                        personnelCached.hsetAllPersonnelInfo(updatePersonnelList);
//                        log.info("修改工单时负责人员定时修改数据数目： {}", personnelTotal);
//                    }
//                }
//            }
        }
    }

    /**
     * 清除P开头的工单
     *
     * @return void
     * @author ljx
     * @time 2024/8/19 12:54
     */
    @Override
    @Transactional
    public void cleanJobNum() {
        List<Job> jobs = jobMapper.selectList(null);
//        redisCached.set(RedisConstant.EMP_NO_LAST_NUMBER, NumericalConstants.ONE);
//        log.info("工号最后停留的编号数值设置成功{}", redisCached.get(RedisConstant.EMP_NO_LAST_NUMBER));
        //先设置成半小时
//        redisCached.set(RedisConstant.WORK_SYNC_TIME, 60 * 30);
//        log.info("工单同步时间间隔设置成功{}", redisCached.get(RedisConstant.WORK_SYNC_TIME));
        if (!CollectionUtils.isEmpty(jobs)) {
            List<Job> jobsList = jobs.stream().filter(job -> job.getJobNum().substring(0, 1).toUpperCase().equals("P")).collect(Collectors.toList());
            List<Long> ids = jobsList.stream().map(Job::getJobId).collect(Collectors.toList());
            int count = jobMapper.deleteBatchIds(ids);
//            log.info("工单删除数量：{}", count);
            if (count > 0) {
                jobsList.forEach(job -> {
                    redisCached.hdel(RedisConstant.JOB_ORDER_INFO_KEY, job.getJobId() + "");
                    redisCached.srem(RedisConstant.JOB_NUM_SET, job.getJobNum());
                });
//                log.info("缓存删除完成");
            }
        }
    }

    /**
     * 改绑场景名称
     *
     * @param oldScene
     * @param newScene
     * @return void
     * @author ljx
     * @time 2024/8/19 18:21
     */
    @Override
    @Transactional
    public void changeBindScene(String oldScene, String newScene) {
        List<Job> jobs = jobMapper.selectList(Wrappers.<Job>lambdaQuery().eq(Job::getWorkArea, oldScene));
        if (!CollectionUtils.isEmpty(jobs)) {
            int total = 0;
            for (Job job : jobs) {
                job.setWorkArea(newScene);
                int count = jobMapper.updateById(job);
                if (count > 0) {
                    total += count;
                    redisCached.hset(RedisConstant.JOB_ORDER_INFO_KEY, job.getJobId() + "", JSON.toJSONString(job));
                }
            }
//            log.info("改绑完成,改绑总数量：{}", total);
        }

    }

    /**
     * 重置同步获取负责人联系方式
     *
     * @return void
     * @author ljx
     * @time 2024/9/2 11:46
     */
    @Override
    @Transactional
    public void setPersonnelPhone() {
        List<Personnel> addPersonnelList = new LinkedList<>();
        List<Personnel> personnelList = personnelCached.hgetAllPersonnelInfo();
        if (!CollectionUtils.isEmpty(personnelList)) {
//            log.info("缓存负责人数量：{}", personnelList.size());
//            log.info("修改前缓存负责人信息：{}", personnelList.get(0));
            Map<String, Personnel> personnelMap = personnelList.stream().collect(Collectors.toMap(Personnel::getDirectorId, Function.identity()));
            List<String> directorIds = personnelList.stream().map(Personnel::getDirectorId).collect(Collectors.toSet()).stream().collect(Collectors.toList());
            //分批请求负责人员，每批100
            List<List<String>> directorIdLists = DataUtil.splitData(directorIds, 100);
            for (List<String> directorIdList : directorIdLists) {
                String join = String.join(",", directorIdList);
                List<Personnel> list = ExternalAccessHttp.personnelInfoHttpGet(openApiConfig.syncJobUrl, join);
                if (!CollectionUtils.isEmpty(list)) {
//                    log.info("本批负责人同步数量：{}", list.size());
                    addPersonnelList.addAll(list);
                }
            }
            List<Personnel> updatePersonnelList = new LinkedList<>();
            if (!CollectionUtils.isEmpty(addPersonnelList)) {
//                log.info("负责人同步总数量：{}", addPersonnelList.size());
                for (Personnel personnel : addPersonnelList) {
                    Personnel oldPersonnel = personnelMap.get(personnel.getDirectorId());
                    if (oldPersonnel != null) {
                        oldPersonnel.setPhone(personnel.getPhone());
                        updatePersonnelList.add(oldPersonnel);
                    }
                }
                //修改内容
                Integer count = personnelMapper.updatePhone(updatePersonnelList);
                if (count > 0) {
//                    log.info("负责人联系方式修改数量：{}", count);
                    personnelCached.hsetAllPersonnelInfo(updatePersonnelList);
//                    log.info("修改后缓存负责人信息：{}", updatePersonnelList.get(0));
                    List<Personnel> personnelList1 = personnelMapper.selectList(null);
//                    log.info("修改后数据库负责人信息：{}", personnelList1.get(0));
                }
            }
        }
    }

    /**
     * 清除脏数据
     *
     * @return void
     * @author ljx
     * @time 2024/9/19 19:07
     */
    @Override
    public void clearDirtyData() {
        List<WorkPersonnel> workPersonnelList = workPersonnelMapper.selectList(null);
        log.info("作业人员数量：{}", workPersonnelList.size());
        for (WorkPersonnel workPersonnel : workPersonnelList) {
            String temporaryEmpNo = workPersonnel.getTemporaryEmpNo();
            //人员缓存
            workPersonnelCached.delWorkPersonnelInfo(temporaryEmpNo);
            log.info("清除作业人员信息缓存,临时工号：{}", temporaryEmpNo);
            BindCardDTO bindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_EMP_NO_KEY + temporaryEmpNo);
            if (bindCardDTO != null) {
                //绑卡缓存
                bindCardCached.hdelBindCardInfo(temporaryEmpNo, bindCardDTO.getDeviceName());
                log.info("清除绑卡信息缓存,临时工号：{}", temporaryEmpNo);
            }
            //分组下对应的作业人员或者负责人信息缓存
            Integer groupId = workPersonnel.getGroupId();
            if (groupId != null && groupId != 0) {
                redisCached.hdel(RedisConstant.GROUP_PERSONNEL_INFO + groupId, temporaryEmpNo);
                log.info("清除分组下对应的作业人员或者负责人信息缓存,临时工号：{}", temporaryEmpNo);
            }
        }
        int delete = workPersonnelMapper.delete(null);
        log.info("删除作业人员数量：{}", delete);
    }

    /**
     * 基站设备状态定时同步任务
     *
     * @return void
     * @author ljx
     * @time 2025/2/24 17:36
     */
    @Override
    @Transactional
    public void syncDeviceStatusInfo() {
        List<HttpTagInfoVO> httpTagInfoVOS = new ArrayList<>();
        //基站设备
        String str = HttpUtil.get(openApiConfig.ipHost + ApiConstants.GET_ALL_ANCHOR);
        if (StringUtils.isNotBlank(str)) {
            JSONObject result = JSONObject.parseObject(str);
            if (result.getInteger("code").equals(JsonResultEnum.SUCCESS.getCode())) {
                JSONArray jsonArray = result.getJSONArray("data");
                if (!CollectionUtils.isEmpty(jsonArray)) {
                    httpTagInfoVOS = jsonArray.toJavaList(HttpTagInfoVO.class);
                }
            }
        }
        List<LocationDeviceLog> addLocationDeviceLogList = new LinkedList<>();
        List<LocationDeviceLog> updateLocationDeviceLogList = new LinkedList<>();
        if (!CollectionUtils.isEmpty(httpTagInfoVOS)) {
            Date date = new Date();
            for (HttpTagInfoVO httpTagInfoVO : httpTagInfoVOS) {
                String sn = httpTagInfoVO.getSn();
                Boolean online = httpTagInfoVO.getOnline();
                if (online == null || StringUtils.isBlank(sn)) {
                    continue;
                }
                LocationDevice locationDevice = locationDeviceCached.hgetLocationDeviceInfo(sn);
                if (locationDevice == null) {
                    continue;
                }
                LocationDeviceLog lastLocationDeviceLog = locationDeviceLogMapper.selectLast(sn);
                if (lastLocationDeviceLog == null) {
                    //代表第一次执行定时任务，新增一条记录
                    addLocationDeviceLogList.add(new LocationDeviceLog(locationDevice, online));
                    continue;
                }
                Integer type = lastLocationDeviceLog.getType();
                //不管在线离线都修改上一条记录的时间
                updateLocationDeviceLogList.add(new LocationDeviceLog(lastLocationDeviceLog.getId(), date));
                //离线
                if (type.equals(NumericalConstants.ONE)) {
                    //如果上次记录与本次状态不同则新增一条记录
                    if (online) {
                        addLocationDeviceLogList.add(new LocationDeviceLog(locationDevice, online));
                    }
                } else {//在线
                    //如果上次记录与本次状态不同则新增一条记录
                    if (!online) {
                        addLocationDeviceLogList.add(new LocationDeviceLog(locationDevice, online));
                    }
                }
            }
        }
        if (!CollectionUtils.isEmpty(addLocationDeviceLogList)) {
            locationDeviceLogMapper.batchAdd(addLocationDeviceLogList);
        }
        if (!CollectionUtils.isEmpty(updateLocationDeviceLogList)) {
            locationDeviceLogMapper.batchUpdate(updateLocationDeviceLogList);
        }
    }

}
